#include "supports.h"
#include "ch32v30x_libs.h"
#include "EPaper.hpp"
#include "Pin_ch32v.hpp"
#include "SoftSPI.hpp"

EPaper *epaper;
SoftSPI *spi;
Pin *sck;
Pin *mosi;
Pin *nss;
Pin *dc;
Pin *reset;
Pin *busy;

extern const uint8_t charset_ascii[] = { 
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*" ",32*/

0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,
0x10,0x10,0x00,0x00,0x10,0x10,0x00,0x00,/*"!",33*/

0x00,0x12,0x24,0x24,0x48,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*""",34*/

0x00,0x00,0x00,0x12,0x12,0x12,0x7E,0x24,
0x24,0x24,0x7E,0x24,0x24,0x24,0x00,0x00,/*"#",35*/

0x00,0x00,0x08,0x3C,0x4A,0x4A,0x48,0x38,
0x0C,0x0A,0x0A,0x4A,0x4A,0x3C,0x08,0x08,/*"$",36*/

0x00,0x00,0x00,0x44,0xA4,0xA8,0xA8,0xB0,
0x54,0x1A,0x2A,0x2A,0x4A,0x44,0x00,0x00,/*"%",37*/

0x00,0x00,0x00,0x30,0x48,0x48,0x48,0x50,
0x6E,0xA4,0x94,0x98,0x89,0x76,0x00,0x00,/*"&",38*/

0x00,0x60,0x20,0x20,0x40,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"'",39*/

0x00,0x02,0x04,0x08,0x08,0x10,0x10,0x10,
0x10,0x10,0x10,0x08,0x08,0x04,0x02,0x00,/*"(",40*/

0x00,0x40,0x20,0x10,0x10,0x08,0x08,0x08,
0x08,0x08,0x08,0x10,0x10,0x20,0x40,0x00,/*")",41*/

0x00,0x00,0x00,0x00,0x10,0x10,0xD6,0x38,
0x38,0xD6,0x10,0x10,0x00,0x00,0x00,0x00,/*"*",42*/

0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,
0x7F,0x08,0x08,0x08,0x00,0x00,0x00,0x00,/*"+",43*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x60,0x20,0x20,0x40,/*",",44*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"-",45*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,/*".",46*/

0x00,0x00,0x02,0x04,0x04,0x04,0x08,0x08,
0x10,0x10,0x10,0x20,0x20,0x40,0x40,0x00,/*"/",47*/

0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,
0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00,/*"0",48*/

0x00,0x00,0x00,0x08,0x38,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00,/*"1",49*/

0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x02,
0x04,0x08,0x10,0x20,0x42,0x7E,0x00,0x00,/*"2",50*/

0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x04,
0x18,0x04,0x02,0x42,0x42,0x3C,0x00,0x00,/*"3",51*/

0x00,0x00,0x00,0x04,0x0C,0x0C,0x14,0x24,
0x24,0x44,0x7F,0x04,0x04,0x1F,0x00,0x00,/*"4",52*/

0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x78,
0x44,0x02,0x02,0x42,0x44,0x38,0x00,0x00,/*"5",53*/

0x00,0x00,0x00,0x18,0x24,0x40,0x40,0x5C,
0x62,0x42,0x42,0x42,0x22,0x1C,0x00,0x00,/*"6",54*/

0x00,0x00,0x00,0x7E,0x42,0x04,0x04,0x08,
0x08,0x10,0x10,0x10,0x10,0x10,0x00,0x00,/*"7",55*/

0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,
0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00,/*"8",56*/

0x00,0x00,0x00,0x38,0x44,0x42,0x42,0x42,
0x46,0x3A,0x02,0x02,0x24,0x18,0x00,0x00,/*"9",57*/

0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,
0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,/*":",58*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,/*";",59*/

0x00,0x00,0x00,0x02,0x04,0x08,0x10,0x20,
0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00,/*"<",60*/

0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,
0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,/*"=",61*/

0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,
0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00,/*">",62*/

0x00,0x00,0x00,0x3C,0x42,0x42,0x62,0x04,
0x08,0x08,0x08,0x00,0x18,0x18,0x00,0x00,/*"?",63*/

0x00,0x00,0x00,0x38,0x44,0x5A,0xAA,0xAA,
0xAA,0xAA,0xAA,0x5C,0x42,0x3C,0x00,0x00,/*"@",64*/

0x00,0x00,0x00,0x10,0x10,0x18,0x28,0x28,
0x24,0x3C,0x44,0x42,0x42,0xE7,0x00,0x00,/*"A",65*/

0x00,0x00,0x00,0xF8,0x44,0x44,0x44,0x78,
0x44,0x42,0x42,0x42,0x44,0xF8,0x00,0x00,/*"B",66*/

0x00,0x00,0x00,0x3E,0x42,0x42,0x80,0x80,
0x80,0x80,0x80,0x42,0x44,0x38,0x00,0x00,/*"C",67*/

0x00,0x00,0x00,0xF8,0x44,0x42,0x42,0x42,
0x42,0x42,0x42,0x42,0x44,0xF8,0x00,0x00,/*"D",68*/

0x00,0x00,0x00,0xFC,0x42,0x48,0x48,0x78,
0x48,0x48,0x40,0x42,0x42,0xFC,0x00,0x00,/*"E",69*/

0x00,0x00,0x00,0xFC,0x42,0x48,0x48,0x78,
0x48,0x48,0x40,0x40,0x40,0xE0,0x00,0x00,/*"F",70*/

0x00,0x00,0x00,0x3C,0x44,0x44,0x80,0x80,
0x80,0x8E,0x84,0x44,0x44,0x38,0x00,0x00,/*"G",71*/

0x00,0x00,0x00,0xE7,0x42,0x42,0x42,0x42,
0x7E,0x42,0x42,0x42,0x42,0xE7,0x00,0x00,/*"H",72*/

0x00,0x00,0x00,0x7C,0x10,0x10,0x10,0x10,
0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"I",73*/

0x00,0x00,0x00,0x3E,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x88,0xF0,/*"J",74*/

0x00,0x00,0x00,0xEE,0x44,0x48,0x50,0x70,
0x50,0x48,0x48,0x44,0x44,0xEE,0x00,0x00,/*"K",75*/

0x00,0x00,0x00,0xE0,0x40,0x40,0x40,0x40,
0x40,0x40,0x40,0x40,0x42,0xFE,0x00,0x00,/*"L",76*/

0x00,0x00,0x00,0xEE,0x6C,0x6C,0x6C,0x6C,
0x6C,0x54,0x54,0x54,0x54,0xD6,0x00,0x00,/*"M",77*/

0x00,0x00,0x00,0xC7,0x62,0x62,0x52,0x52,
0x4A,0x4A,0x4A,0x46,0x46,0xE2,0x00,0x00,/*"N",78*/

0x00,0x00,0x00,0x38,0x44,0x82,0x82,0x82,
0x82,0x82,0x82,0x82,0x44,0x38,0x00,0x00,/*"O",79*/

0x00,0x00,0x00,0xFC,0x42,0x42,0x42,0x42,
0x7C,0x40,0x40,0x40,0x40,0xE0,0x00,0x00,/*"P",80*/

0x00,0x00,0x00,0x38,0x44,0x82,0x82,0x82,
0x82,0x82,0x82,0xB2,0x4C,0x38,0x06,0x00,/*"Q",81*/

0x00,0x00,0x00,0xFC,0x42,0x42,0x42,0x7C,
0x48,0x48,0x44,0x44,0x42,0xE3,0x00,0x00,/*"R",82*/

0x00,0x00,0x00,0x3E,0x42,0x42,0x40,0x20,
0x18,0x04,0x02,0x42,0x42,0x7C,0x00,0x00,/*"S",83*/

0x00,0x00,0x00,0xFE,0x92,0x10,0x10,0x10,
0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,/*"T",84*/

0x00,0x00,0x00,0xE7,0x42,0x42,0x42,0x42,
0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00,/*"U",85*/

0x00,0x00,0x00,0xE7,0x42,0x42,0x44,0x24,
0x24,0x28,0x28,0x18,0x10,0x10,0x00,0x00,/*"V",86*/

0x00,0x00,0x00,0xD6,0x54,0x54,0x54,0x54,
0x54,0x6C,0x28,0x28,0x28,0x28,0x00,0x00,/*"W",87*/

0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x18,
0x18,0x18,0x24,0x24,0x42,0xE7,0x00,0x00,/*"X",88*/

0x00,0x00,0x00,0xEE,0x44,0x44,0x28,0x28,
0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,/*"Y",89*/

0x00,0x00,0x00,0x7E,0x84,0x04,0x08,0x08,
0x10,0x20,0x20,0x42,0x42,0xFC,0x00,0x00,/*"Z",90*/

0x00,0x1E,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x10,0x10,0x10,0x10,0x10,0x1E,0x00,/*"[",91*/

0x00,0x00,0x40,0x20,0x20,0x20,0x10,0x10,
0x10,0x08,0x08,0x04,0x04,0x04,0x02,0x02,/*"\",92*/

0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x78,0x00,/*"]",93*/

0x00,0x18,0x24,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"^",94*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,/*"_",95*/

0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"`",96*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,
0x44,0x0C,0x34,0x44,0x4C,0x36,0x00,0x00,/*"a",97*/

0x00,0x00,0x00,0x00,0xC0,0x40,0x40,0x58,
0x64,0x42,0x42,0x42,0x64,0x58,0x00,0x00,/*"b",98*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,
0x22,0x40,0x40,0x40,0x22,0x1C,0x00,0x00,/*"c",99*/

0x00,0x00,0x00,0x00,0x06,0x02,0x02,0x3E,
0x42,0x42,0x42,0x42,0x46,0x3B,0x00,0x00,/*"d",100*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,
0x42,0x42,0x7E,0x40,0x42,0x3C,0x00,0x00,/*"e",101*/

0x00,0x00,0x00,0x00,0x0C,0x12,0x10,0x7C,
0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"f",102*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,
0x44,0x44,0x38,0x40,0x3C,0x42,0x42,0x3C,/*"g",103*/

0x00,0x00,0x00,0x00,0xC0,0x40,0x40,0x5C,
0x62,0x42,0x42,0x42,0x42,0xE7,0x00,0x00,/*"h",104*/

0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x70,
0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"i",105*/

0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x1C,
0x04,0x04,0x04,0x04,0x04,0x04,0x44,0x78,/*"j",106*/

0x00,0x00,0x00,0x00,0xC0,0x40,0x40,0x4E,
0x48,0x50,0x70,0x48,0x44,0xEE,0x00,0x00,/*"k",107*/

0x00,0x00,0x00,0x10,0x70,0x10,0x10,0x10,
0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"l",108*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,
0x49,0x49,0x49,0x49,0x49,0xED,0x00,0x00,/*"m",109*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,
0x62,0x42,0x42,0x42,0x42,0xE7,0x00,0x00,/*"n",110*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,
0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00,/*"o",111*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD8,
0x64,0x42,0x42,0x42,0x64,0x58,0x40,0xE0,/*"p",112*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1A,
0x26,0x42,0x42,0x42,0x26,0x1A,0x02,0x07,/*"q",113*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,
0x32,0x20,0x20,0x20,0x20,0xF8,0x00,0x00,/*"r",114*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,
0x42,0x40,0x3C,0x02,0x42,0x7C,0x00,0x00,/*"s",115*/

0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x7C,
0x10,0x10,0x10,0x10,0x12,0x0C,0x00,0x00,/*"t",116*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC6,
0x42,0x42,0x42,0x42,0x46,0x3B,0x00,0x00,/*"u",117*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,
0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00,/*"v",118*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDB,
0x89,0x4A,0x5A,0x54,0x24,0x24,0x00,0x00,/*"w",119*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x76,
0x24,0x18,0x18,0x18,0x24,0x6E,0x00,0x00,/*"x",120*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE7,
0x42,0x24,0x24,0x18,0x18,0x10,0x10,0x60,/*"y",121*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,
0x44,0x08,0x10,0x10,0x22,0x7E,0x00,0x00,/*"z",122*/

0x00,0x03,0x04,0x04,0x04,0x04,0x04,0x04,
0x08,0x04,0x04,0x04,0x04,0x04,0x03,0x00,/*"{",123*/

0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,/*"|",124*/

0x00,0xC0,0x20,0x20,0x20,0x20,0x20,0x20,
0x10,0x20,0x20,0x20,0x20,0x20,0xC0,0x00,/*"}",125*/

0x20,0x5A,0x04,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"~",126*/
 
};

void createScreen(){
    sck = PinFactory::getPin(GPIO::A,5,PinMode::Output);
    mosi = PinFactory::getPin(GPIO::A,7,PinMode::Output);
    nss = PinFactory::getPin(GPIO::A,8,PinMode::Output);
    dc = PinFactory::getPin(GPIO::A,2,PinMode::Output);
    reset = PinFactory::getPin(GPIO::A,3,PinMode::Output);
    busy = PinFactory::getPin(GPIO::A,1,PinMode::Input_floating);
    spi = new SoftSPI(mosi,nullptr,sck);
    epaper = new EPaper(spi,nss,dc,reset,busy,296,128);
}

void Draw_Line(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,Color color);
void Draw_Circle(uint16_t x0,uint16_t y0,uint16_t R,Color color);
void Draw_Char(uint16_t x,uint16_t y,uint8_t ch,Color color);
void Draw_String(uint16_t x0,uint16_t y0,char *str,Color color);

extern "C"
int main(void){
    /* 创建墨水屏 */
    createScreen();

    epaper->clear();

    Color color = {.data = 1};
    /* 绘制一条直线 */
    Draw_Line(15,8,45,8,color);
    Draw_Circle(50,10,3,color);
    
    Draw_String(15,10,(char*)"Hello EPaper",color);
    epaper->refresh();

    Sys_delayMs(5000);

    epaper->clear();

    epaper->sleep();
    while ( true ){
    }
}

/************ 绘图库实现 ************/

int16_t abs(int16_t n){
    return n<0 ? -n : n;
}

void Draw_Line(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,Color color){
    int16_t d,dx,dy,x,y;
    /* 判断最大位移方向 */
    if(abs(y2-y1)<abs(x2-x1)){
        //x方向为最大位移方向，判断两点位置
        if(x2<x1){
            x=x2;
            y=y2;
            x2=x1;
            y2=y1;
            x1=x;
            y1=y;
        }else{
            x=x1;
            y=y1;
        }
        dx=x2-x1;
        dy=y2-y1;
        epaper->setPixel(x,y,color);  //绘制第一个点
        //判断k是否小于0
        if((y2-y1)*(x2-x1)>=0){
            //k大于0
            d=-dx;
            for(x=x1+1;x<=x2;x++){
                if(d>0){
                    y++;
                    d-=2*dx;
                }
                d+=2*dy;
                epaper->setPixel(x,y,color);
            }
        }else{
            //k小于0
            d=dx;
            for(x=x1+1;x<=x2;x++){
                if(d<0){
                    y--;
                    d+=2*dx;
                }
                d+=2*dy;
                epaper->setPixel(x,y,color);
            }
        } 
    }else{
        //y方向为最大位移方向,判断两点位置
        if(y2<y1){
            x=x2;
            y=y2;
            x2=x1;
            y2=y1;
            x1=x;
            y1=y;
        }else{
            x=x1;
            y=y1;
        }
        dx=x2-x1;
        dy=y2-y1;
        //绘制第一个点
        epaper->setPixel(x,y,color);
        if((y2-y1)*(x2-x1)>=0){
            //如果k大于0
            d=-dy;
            for(y=y1+1;y<=y2;y++){
                if(d>0){
                    x++;
                    d-=2*dy;
                }
                d+=2*dx;
                epaper->setPixel(x,y,color);
            }
        }else{
            //k<0
            d=dy;
            for(y=y1+1;y<=y2;y++){
                if(d<0){
                    x--;
                    d+=2*dy;
                }
                d+=2*dx;
                epaper->setPixel(x,y,color);
            }
        }
    }
}

void __Draw_CirclePoint(uint16_t x,uint16_t y,uint16_t x0,uint16_t y0,Color color){
    epaper->setPixel(x+x0,y+y0,color);
    epaper->setPixel(x+x0,-y+y0,color);
    epaper->setPixel(-x+x0,y+y0,color);
    epaper->setPixel(-x+x0,-y+y0,color);
    epaper->setPixel(y+x0,x+y0,color);
    epaper->setPixel(y+x0,-x+y0,color);
    epaper->setPixel(-y+x0,x+y0,color);
    epaper->setPixel(-y+x0,-x+y0,color);    
}

/* 八分中点Bresenham算法画圆 */

void Draw_Circle(uint16_t x0,uint16_t y0,uint16_t R,Color color){
    int16_t x,y,d;
    d=1-R;
    y=R;
    for(x=0;x<R*0.707;x++){
        __Draw_CirclePoint(x,y,x0,y0,color);
        if(d<=0){
            d=d+2*x+3;
        }else{
            d=d+2*(x-y)+5;
            y--;
        }
    }
}

void Draw_Char(uint16_t x,uint16_t y,uint8_t ch,Color color){
    uint16_t index,p,n;
    uint8_t code;
    index=ch - ' ';
    for(p=0;p<16;p++){
        code=charset_ascii[index*16+p];
         for(n=0;n<8;n++){
            if(code&0x80){
                epaper->setPixel(n+x,p+y,color);
            }
            code<<=1;
        }
    }
}

void Draw_String(uint16_t x0,uint16_t y0,char *str,Color color){
    uint16_t x,y;
    x=x0;
    y=y0;
    while(*str!=0){
        if(*str=='\n'){
            y+=16;
            x=x0;
            str++;
            continue;
        }
        Draw_Char(x,y,*str++,color);
        x+=8;
    }
}
